#ifndef __SDIO_H__
#define __SDIO_H__



#include "drv_gpio.h"
#include "drv_clock.h"

#define MMC0_BASE_ADDR     0x01C0F000

struct tina_mmc{
    volatile rt_uint32_t gctl_reg;            /* (0x000) */
    volatile rt_uint32_t ckcr_reg;            /* (0x004) */
    volatile rt_uint32_t tmor_reg;            /* (0x008) */
    volatile rt_uint32_t bwdr_reg;            /* (0x00C) */
    volatile rt_uint32_t bksr_reg;            /* (0x010) */
    volatile rt_uint32_t bycr_reg;            /* (0x014) */
    volatile rt_uint32_t cmdr_reg;            /* (0x018) */
    volatile rt_uint32_t cagr_reg;            /* (0x01C) */
    volatile rt_uint32_t resp0_reg;           /* (0x020) */
    volatile rt_uint32_t resp1_reg;           /* (0x024) */
    volatile rt_uint32_t resp2_reg;           /* (0x028) */
    volatile rt_uint32_t resp3_reg;           /* (0x02C) */
    volatile rt_uint32_t imkr_reg;            /* (0x030) */
    volatile rt_uint32_t misr_reg;            /* (0x034) */
    volatile rt_uint32_t risr_reg;            /* (0x038) */
    volatile rt_uint32_t star_reg;            /* (0x03C) */
    volatile rt_uint32_t fwlr_reg;            /* (0x040) */
    volatile rt_uint32_t funs_reg;            /* (0x044) */
    volatile rt_uint32_t cbcr_reg;            /* (0x048) */
    volatile rt_uint32_t bbcr_reg;            /* (0x04C) */
    volatile rt_uint32_t dbgc_reg;            /* (0x050) */
    volatile rt_uint32_t reserved0;
    volatile rt_uint32_t a12a_reg;            /* (0x058) */
    volatile rt_uint32_t reserved1[7];
    volatile rt_uint32_t hwrst_reg;           /* (0x078) */
    volatile rt_uint32_t reserved2;
    volatile rt_uint32_t dmac_reg;            /* (0x080) */
    volatile rt_uint32_t dlba_reg;            /* (0x084) */
    volatile rt_uint32_t idst_reg;            /* (0x088) */
    volatile rt_uint32_t idie_reg;            /* (0x08C) */
    volatile rt_uint32_t chda_reg;            /* (0x090) */
    volatile rt_uint32_t cbda_reg;            /* (0x094) */
    volatile rt_uint32_t reserved3[26];
    volatile rt_uint32_t card_thldc_reg;      /* (0x100) */
    volatile rt_uint32_t reserved4[2];
    volatile rt_uint32_t emmc_dsbd_reg;       /* (0x10c) */
    volatile rt_uint32_t reserved5[12];
    volatile rt_uint32_t reserved6[48];
    volatile rt_uint32_t fifo_reg;            /* (0x200) */
};

typedef struct tina_mmc *tina_mmc_t;

#define ALIGN(n)                    __attribute__((aligned(n)))
  /* class 1 */
#define GO_IDLE_STATE         0   /* bc                          */
#define SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
#define ALL_SEND_CID          2   /* bcr                     R2  */
#define SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
#define SET_DSR               4   /* bc   [31:16] RCA            */
#define SWITCH                6   /* ac   [31:0] See below   R1b */
#define SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
#define SEND_EXT_CSD          8   /* adtc                    R1  */
#define SEND_CSD              9   /* ac   [31:16] RCA        R2  */
#define SEND_CID             10   /* ac   [31:16] RCA        R2  */
#define READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
#define STOP_TRANSMISSION    12   /* ac                      R1b */
#define SEND_STATUS          13   /* ac   [31:16] RCA        R1  */
#define GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
#define SPI_READ_OCR         58   /* spi                  spi_R3 */
#define SPI_CRC_ON_OFF       59   /* spi  [0:0] flag      spi_R1 */

  /* class 2 */
#define SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
#define READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
#define READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */

  /* class 3 */
#define WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */

  /* class 4 */
#define SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
#define WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
#define WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
#define PROGRAM_CID          26   /* adtc                    R1  */
#define PROGRAM_CSD          27   /* adtc                    R1  */

  /* class 6 */
#define SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
#define CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
#define SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */

  /* class 5 */
#define ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
#define ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
#define ERASE                38   /* ac                      R1b */

  /* class 9 */
#define FAST_IO              39   /* ac   <Complex>          R4  */
#define GO_IRQ_STATE         40   /* bcr                     R5  */

  /* class 7 */
#define LOCK_UNLOCK          42   /* adtc                    R1b */

  /* class 8 */
#define APP_CMD              55   /* ac   [31:16] RCA        R1  */
#define GEN_CMD              56   /* adtc [0] RD/WR          R1  */


/* SD commands                           type  argument     response */
  /* class 0 */
/* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
#define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */

  /* class 10 */
#define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */

  /* Application commands */
#define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
#define SD_APP_SEND_NUM_WR_BLKS  22   /* adtc                    R1  */
#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
#define SD_APP_SEND_SCR          51   /* adtc                    R1  */

#define SCR_SPEC_VER_0		0	/* Implements system specification 1.0 - 1.01 */
#define SCR_SPEC_VER_1		1	/* Implements system specification 1.10 */
#define SCR_SPEC_VER_2		2	/* Implements system specification 2.00 */


/* SDIO commands                                          type  argument     response */
#define SD_IO_SEND_OP_COND          5 /* bcr  [23:0] OCR         R4  */
#define SD_IO_RW_DIRECT            52 /* ac   [31:0] See below   R5  */
#define SD_IO_RW_EXTENDED          53 /* adtc [31:0] See below   R5  */


/* CMD52 arguments */
#define SDIO_ARG_CMD52_READ             (0<<31)
#define SDIO_ARG_CMD52_WRITE            (1u<<31)
#define SDIO_ARG_CMD52_FUNC_SHIFT       28
#define SDIO_ARG_CMD52_FUNC_MASK        0x7
#define SDIO_ARG_CMD52_RAW_FLAG         (1u<<27)
#define SDIO_ARG_CMD52_REG_SHIFT        9
#define SDIO_ARG_CMD52_REG_MASK         0x1ffff
#define SDIO_ARG_CMD52_DATA_SHIFT       0
#define SDIO_ARG_CMD52_DATA_MASK        0xff
#define SDIO_R5_DATA(resp)            ((resp)[0] & 0xff)

/* CMD53 arguments */
#define SDIO_ARG_CMD53_READ             (0<<31)
#define SDIO_ARG_CMD53_WRITE            (1u<<31)
#define SDIO_ARG_CMD53_FUNC_SHIFT       28
#define SDIO_ARG_CMD53_FUNC_MASK        0x7
#define SDIO_ARG_CMD53_BLOCK_MODE       (1u<<27)
#define SDIO_ARG_CMD53_INCREMENT        (1u<<26)
#define SDIO_ARG_CMD53_REG_SHIFT        9
#define SDIO_ARG_CMD53_REG_MASK         0x1ffff
#define SDIO_ARG_CMD53_LENGTH_SHIFT     0
#define SDIO_ARG_CMD53_LENGTH_MASK      0x1ff
#define SDIO_ARG_CMD53_LENGTH_MAX       511

/*cmd reg*/

#define VAL_CMD_LOAD             (1u<<31)
#define VAL_USE_HOLDREG         (1u<<29)
#define VAL_VOL_SW_CMD11        (1u<<28)
#define VAL_BOOT_ABT            (1u<<27)
#define VAL_EXP_BOOT_ACK        (1u<<26)
#define VAL_BOOT_MOD(mode)      ((mode & 0x03)<<24)
#define VAL_PRG_CLK             (1u<<21)
#define VAL_SEND_INIT_SEQ        (1u<<15)
#define VAL_STOP_ABT_CMD        (1u<<14)

#define VAL_WAIT_PRE_OVER       (1u<<13)
#define VAL_STOP_CMD_FLAG       (1u<<12)
#define VAL_TRANS_MODE_STREAM   (1u<<11)
#define VAL_TRANS_DIR_WRITE     (1u<<10)
#define VAL_WITH_DATA_TRANS     (1u<<9)

#define VAL_CHK_RESP_CRC        (1u<<8)
#define VAL_LONG_RESP           (1u<<7)
#define VAL_CMD_WITH_RESP       (1u<<6)

#define BIT(x)              (1<<(x))
#define SDXC_RESPONSE_CMD        BIT(6)
#define SDXC_LONG_RESPONSE_CMD   BIT(7)
#define SDXC_CHECK_CRC_CMD       BIT(8)
#define SDXC_HAS_DATA_CMD        BIT(9)
#define SDXC_WRITE_CMD           BIT(10)
#define SDXC_STEAM_CMD           BIT(11)
#define SDXC_AUTO_STOP_CMD       BIT(12)
#define SDXC_WAIT_OVER_CMD       BIT(13)
#define SDXC_ABOUT_CMD           BIT(14)
#define SDXC_SEND_INIT_CMD       BIT(15)
#define SDXC_UPDATE_CLOCK_CMD    BIT(21)
#define SDXC_LOAD_CMD            BIT(31)

struct fat32{
  unsigned int fat1;      //fat1 sector addr
  unsigned int dbr;       //dbr sector addr
  unsigned int root;      //rootdir sector addr
  unsigned int fatsize;   //sizeof fat in sectors
  unsigned int cusize;    //sizeof cu in sectors

};
typedef struct fat32 *fat32_t;

typedef struct bfile
{
    unsigned int filesize;
    unsigned int start_cu;
    unsigned int num_of_cus;
    unsigned int num_of_secs;
}bfile,*bfile_t;


void sdio_init(void);
void sendcmd(rt_int32_t cmd,rt_int32_t arg,rt_int32_t cmdval);
void read_resp(rt_uint32_t *resp);
void sdio_read_sector(rt_uint32_t addr_sec,rt_uint8_t *buf);
void sdio_config_clk_width(rt_uint32_t clk,rt_uint32_t width);
void switch_HS4bit_mode(void);
void sdio_write_sector(rt_uint32_t addr_sec,rt_uint8_t *buf);

int cpfile_to_ram(char *file,rt_uint32_t addr_ram);

rt_uint32_t get_sector_addr_bycuNo(fat32_t pfat,rt_uint32_t cuNo);
rt_uint32_t get_nextcuNo_byfatTable(fat32_t pfat,rt_uint32_t cuNo);

#endif